﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using Common.Entities;
using System.Xml;

namespace Common
{
	public enum Versions
	{
		NotSelected,
		Version8,
		Version9,
		Version10
	}

	public class VisualStudioHelper
	{
		private int processedSolutions = 0;
		private int processedProjects = 0;
		private int processedSource = 0;
		private int totalProcessed = 0;
		private int partialsProcessed = 0;

		public event EventHandler<FileProcessedEventArgs> FileProcessed;
		public event EventHandler<EventArgs> Completed;

		private Versions ConvertTo;
		private bool m_isBackup = false;

		public VisualStudioHelper()
		{
			ConvertTo = Versions.NotSelected;
		}

		//
		// Get the Solution file "format version".  Also verifies we have a valid solution file
		//
		private double GetVersion(string FileName)
		{
			if (string.IsNullOrEmpty(FileName))
				return 0;

			FileStream fs = new FileStream(FileName, FileMode.Open);
			StreamReader sr = new StreamReader(fs);
			string buf = null;
			int linecount = 0;
			double ans = 0.0;

			while (!sr.EndOfStream)
			{
				buf = sr.ReadLine();

				// is this a valid header?
				if (buf.StartsWith("Microsoft Visual Studio Solution File, Format Version"))
				{
					ans = double.Parse(buf.Substring(54), System.Globalization.CultureInfo.GetCultureInfo("en-US"));
					break; // TODO: might not be correct. Was : Exit Do
				}

				linecount += 1;
				// A valid solution should have a header at the 1st or 2nd line
				if (linecount > 2)
				{
					break; // TODO: might not be correct. Was : Exit Do
				}
			}

			sr.Close();
			fs.Close();

			switch (ans.ToString())
			{
				case "0":
					throw new ApplicationException("This doesn't appear to be a valid solution file");
				case "7.0":
					throw new ApplicationException("Conversion of VS.Net (v7.0) solutions is not supported");
				case "8.0":
					throw new ApplicationException("Conversion of VS2003 (v7.1) solutions is not supported");
			}

			return ans;
		}

		//
		// Make a backup copy of the file
		//
		private void MakeBackup(string FileName, double ExistingVersion)
		{
			string Backup = "";

			// remember, ExistingVersion is the file version #, and not the VS version #
			switch (ExistingVersion.ToString())
			{
				case "9.0":
					Backup = Path.Combine(Path.GetDirectoryName(FileName), Path.GetFileNameWithoutExtension(FileName)) + ".v8" + Path.GetExtension(FileName);
					break;
				case "10.0":
					Backup = Path.Combine(Path.GetDirectoryName(FileName), Path.GetFileNameWithoutExtension(FileName)) + ".v9" + Path.GetExtension(FileName);
					break;
				case "11.0":
					Backup = Path.Combine(Path.GetDirectoryName(FileName), Path.GetFileNameWithoutExtension(FileName)) + ".v10" + Path.GetExtension(FileName);
					break;
				default:
					// not likely
					break;
			}

			File.Copy(FileName, Backup, true);
		}

		private bool ConvertProject(string ProjFile, double ExistingVersion)
		{
			System.Xml.XmlDocument xd = null;
			System.Xml.XmlNamespaceManager xnsm = null;
			System.Xml.XmlNode xn = null;
			System.Xml.XmlNode xtemp = null;
			string temp = null;

			// Did you ask to make a backup copy?
			if (m_isBackup)
			{
				MakeBackup(ProjFile, ExistingVersion);
			}

			xd = new System.Xml.XmlDocument();
			xd.Load(ProjFile);

			xnsm = new System.Xml.XmlNamespaceManager(new System.Xml.NameTable());
			xnsm.AddNamespace("prj", "http://schemas.microsoft.com/developer/msbuild/2003");

			// let's do a quick sanity check to make sure we've got the
			// version that we're expecting.  Hey, it happens
			xn = xd.SelectSingleNode("/prj:Project", xnsm);
			if (xn != null)
			{
				xtemp = xn.Attributes["ToolsVersion"];
				if (xtemp != null)
				{
					// converting to VS2008, but project is already at VS2008
					if (ConvertTo == Versions.Version9 & xtemp.InnerText == "3.5")
					{
						// exit quietly
						return false;
					}
					// converting to VS2010, but project is already at VS2010
					if (ConvertTo == Versions.Version10 & xtemp.InnerText == "4.0")
					{
						// exit quietly
						return false;
					}
				}
				else
				{
					// If converting to VS2005, but project is already at VS2005
					if (ConvertTo == Versions.Version8)
					{
						// exit quietly
						return false;
					}
				}
			}
			else
			{
				// no such node?  That's bad, very bad...
				throw new ApplicationException("Invalid project file");
			}

			// the ToolsVersion attribute (we already have selected that node)
			xn.Attributes.Remove(xn.Attributes["ToolsVersion"]);
			switch (ConvertTo)
			{
				case Versions.Version8:
					break;
				// it gets removed
				case Versions.Version9:
					// add the attribute
					xtemp = xd.CreateAttribute("ToolsVersion");
					xtemp.Value = "3.5";
					xn.Attributes.Append((System.Xml.XmlAttribute)xtemp);
					break;
				case Versions.Version10:
					// add the attribute
					xtemp = xd.CreateAttribute("ToolsVersion");
					xtemp.Value = "4.0";
					xn.Attributes.Append((System.Xml.XmlAttribute)xtemp);
					break;
			}

			// the ProjectVersion element
			xn = xd.SelectSingleNode("/prj:Project/prj:PropertyGroup/prj:ProductVersion", xnsm);
			if (xn != null)
			{
				switch (ConvertTo)
				{
					case Versions.Version8:
						xn.InnerText = "<xml/>";//My.Settings.VS2005_Version;
						break;
					case Versions.Version9:
						xn.InnerText = "<xml/>";//My.Settings.VS2008_Version;
						break;
					case Versions.Version10:
						// not used... strange
						xn.InnerText = "";
						break;
				}
			}

			// the OldToolsVersion element in the first PropertyGoup
			xn = xd.SelectSingleNode("/prj:Project/prj:PropertyGroup", xnsm);
			xtemp = xd.SelectSingleNode("/prj:Project/prj:PropertyGroup/prj:OldToolsVersion", xnsm);
			if (xtemp != null)
			{
				xn.RemoveChild(xtemp);
			}
			switch (ConvertTo)
			{
				case Versions.Version8:
					break;
				// it gets removed
				case Versions.Version9:
					// add a new element
					// Note: this doesn't appear to be added in every project type, but I bet it's harmless
					xtemp = xd.CreateElement("OldToolsVersion", xnsm.LookupNamespace("prj"));
					xtemp.AppendChild(xd.CreateTextNode("2.0"));
					xn.AppendChild(xtemp);
					break;
				case Versions.Version10:
					// add a new element
					// Note: this doesn't appear to be added in every project type, but I bet it's harmless
					xtemp = xd.CreateElement("OldToolsVersion", xnsm.LookupNamespace("prj"));
					xtemp.AppendChild(xd.CreateTextNode("3.5"));
					xn.AppendChild(xtemp);
					break;
			}

			// remove/tweak the optional TargetFrameworkVersion element
			xn = xd.SelectSingleNode("/prj:Project/prj:PropertyGroup", xnsm);
			xtemp = xd.SelectSingleNode("/prj:Project/prj:PropertyGroup/prj:TargetFrameworkVersion", xnsm);
			if (xtemp != null)
			{
				xn.RemoveChild(xtemp);
			}
			switch (ConvertTo)
			{
				case Versions.Version8:
					break;
				// it gets removed
				case Versions.Version9:
					xtemp = xd.CreateElement("TargetFrameworkVersion", xnsm.LookupNamespace("prj"));
					xtemp.AppendChild(xd.CreateTextNode("v3.5"));
					xn.AppendChild(xtemp);
					break;
				case Versions.Version10:
					xtemp = xd.CreateElement("TargetFrameworkVersion", xnsm.LookupNamespace("prj"));
					xtemp.AppendChild(xd.CreateTextNode("v4.0"));
					xn.AppendChild(xtemp);
					break;
			}

			// the optional BootStrapper elements.  I only remove the inappropriate values, I
			// do not attempt to add the newer values
			switch (ConvertTo)
			{
				case Versions.Version8:
					// alter the value for the ProductName element using the older framework tag
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.2.0\"]", xnsm);
					if (xn != null)
					{
						xtemp = xn.SelectSingleNode("prj:ProductName", xnsm);
						xtemp.FirstChild.Value = ".NET Framework 2.0";
					}
					// remove the newer framework options
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.3.0\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.3.5\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Client.3.5\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.3.5.SP1\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Windows.Installer.3.1\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					break;
				case Versions.Version9:
					// alter the value for the ProjectName using the newer framework tag
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.2.0\"]", xnsm);
					if (xn != null)
					{
						xtemp = xn.SelectSingleNode("prj:ProductName", xnsm);
						xtemp.FirstChild.Value = ".NET Framework 2.0 %28x86%29";
					}

					// remove the newer framework options
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Client.3.5\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.3.5.SP1\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Windows.Installer.3.1\"]", xnsm);
					if ((xn != null))
					{
						xn.ParentNode.RemoveChild(xn);
					}
					break;
				case Versions.Version10:
					// alter the value for the ProjectName using the newer framework tag
					xn = xd.SelectSingleNode("/prj:Project/prj:ItemGroup/prj:BootstrapperPackage[@Include=\"Microsoft.Net.Framework.2.0\"]", xnsm);
					if (xn != null)
					{
						xtemp = xn.SelectSingleNode("prj:ProductName", xnsm);
						xtemp.FirstChild.Value = ".NET Framework 2.0 %28x86%29";
					}
					break;
			}

			// The MSBuildToolsPath vs MSBuildBinPath environmental variable.  Oddly enough a fully patched VS2005
			// uses the newer MSBuildToolsPath.  So, this should only be required if you don't have VS2005 SP1 installed.
			// However, I can't detect that, so we take the worst case scenario, and use the older version
			foreach (System.Xml.XmlNode xn_loopVariable in xd.SelectNodes("/prj:Project/prj:Import", xnsm))
			{
				xn = xn_loopVariable;
				xtemp = xn.Attributes["Project"];
				if (xtemp != null)
				{
					temp = xn.Attributes["Project"].Value;
					if (ConvertTo >= Versions.Version9)
					{
						// convert it to the newer MSBuildToolsPath
						if (temp.Contains("MSBuildBinPath"))
						{
							temp = temp.Replace("MSBuildBinPath", "MSBuildToolsPath");
							xtemp.Value = temp;
						}
					}
					else
					{
						// convert it to the older MSBuildBinPath
						if (temp.Contains("MSBuildToolsPath"))
						{
							temp = temp.Replace("MSBuildToolsPath", "MSBuildBinPath");
							xtemp.Value = temp;
						}
					}
				}
			}

			xd.Save(ProjFile);
			return true;
		}

		/// <summary>
		/// Migrates all.
		/// </summary>
		/// <param name="sourceFiles">The source files.</param>
		/// <param name="sourcePath">The source path.</param>
		/// <param name="destinationPath">The destination path.</param>
		private void MigrateAll(FileInfo[] sourceFiles, DirectoryInfo sourcePath, DirectoryInfo destinationPath)
		{
			IEnumerable<FileInfo> filteredFiles =
				from sourceFile in sourceFiles
				where
				   !sourceFile.Directory.Name.Equals("bin", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Directory.Name.Equals("obj", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Directory.Name.Equals("debug", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Extension.Equals(".exe", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Extension.Equals(".exe", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Extension.Equals(".manifest", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Extension.Equals(".suo", StringComparison.InvariantCultureIgnoreCase) &&
				   !sourceFile.Extension.Equals(".gpstate", StringComparison.InvariantCultureIgnoreCase)
				select sourceFile;

			this.totalProcessed = filteredFiles.Count();

			foreach (FileInfo file in filteredFiles)
			{
				string destionationFilePath = file.FullName.Replace(sourcePath.FullName, destinationPath.FullName);

				FileInfo destinationFile = new FileInfo(destionationFilePath);

				if (file.FullName.Equals(destinationFile.FullName, StringComparison.InvariantCultureIgnoreCase))
				{
					////Prevent original file overwrite
					throw new Exception();
				}

				if (!destinationFile.Directory.Exists)
				{
					destinationFile.Directory.Create();
				}

				switch (file.Extension.ToLower())
				{
					case ".sln":
						File.WriteAllText(destinationFile.FullName, this.GetConvertedSolutionFile(file));
						this.processedSolutions++;
						break;
					case ".csproj":
						this.GetConvertedProjectFile(file).Save(destinationFile.FullName);
						this.processedProjects++;
						break;
					case ".cs":
						File.WriteAllText(destinationFile.FullName, this.GetConvertedSourceFile(file));
						this.processedSource++;
						break;
					default:
						file.CopyTo(destinationFile.FullName, true);
						break;
				}

				this.partialsProcessed++;

				this.OnFileProcessed(new FileProcessedEventArgs(file, destinationFile, this.partialsProcessed, this.totalProcessed));
			}

			this.OnCompleted(EventArgs.Empty);
		}

		/// <summary>
		/// Raises the <see cref="E:FileProcessed"/> event.
		/// </summary>
		/// <param name="e">The <see cref="EyeOpen.VisualStudio2005BackMigration.FileProcessedEventArgs"/> instance containing the event data.</param>
		protected virtual void OnFileProcessed(FileProcessedEventArgs e)
		{
			EventHandler<FileProcessedEventArgs> handler = this.FileProcessed;

			if (handler != null)
			{
				handler(this, e);
			}
		}

		/// <summary>
		/// Raises the <see cref="E:Completed"/> event.
		/// </summary>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected virtual void OnCompleted(EventArgs e)
		{
			EventHandler<EventArgs> handler = this.Completed;

			if (handler != null)
			{
				handler(this, e);
			}
		}

		/// <summary>
		/// Gets the converted source file.
		/// </summary>
		/// <param name="file">The file.</param>
		/// <returns></returns>
		private string GetConvertedSourceFile(FileInfo file)
		{
			StringBuilder sourceContent = new StringBuilder(File.ReadAllText(file.FullName));
			sourceContent.Replace("using System.Linq;", string.Empty);
			sourceContent.Replace("using System.Xml.Linq;", string.Empty);
			return sourceContent.ToString();
		}

		/// <summary>
		/// Gets the converted project file.
		/// </summary>
		/// <param name="projectFile">The project file.</param>
		/// <returns></returns>
		private XElement GetConvertedProjectFile(FileInfo projectFile)
		{
			XElement projectContentElement = XElement.Load(projectFile.FullName);
			projectContentElement.Attribute("ToolsVersion").Remove();

			IEnumerable<XElement> nodes = from targetFrameworkNode in projectContentElement.Elements()
										  select targetFrameworkNode;

			XElement targetFrameworkVersion = (from childNode in nodes.Elements()
											   where childNode.Name.LocalName == "TargetFrameworkVersion"
											   select childNode).FirstOrDefault();
			if (targetFrameworkVersion != null)
			{
				targetFrameworkVersion.Remove();
			}

			XElement productVersion = (from childNode in nodes.Elements()
									   where childNode.Name.LocalName == "ProductVersion"
									   select childNode).First();
			productVersion.SetValue("8.0.50727");

			(from childNode in nodes.Elements()
			 where childNode.Name.LocalName == "Reference" && childNode.Value == "3.5"
			 select childNode).Remove();

			XElement import = (from childNode in projectContentElement.Elements()
							   where childNode.Name.LocalName == "Import" && childNode.Attribute("Project").Value == @"$(MSBuildToolsPath)\Microsoft.CSharp.targets"
							   select childNode).FirstOrDefault();

			if (import != null)
			{
				import.Attribute("Project").Value = import.Attribute("Project").Value.Replace("MSBuildToolsPath", "MSBuildBinPath");
			}

			return projectContentElement;
		}

		/// <summary>
		/// Gets the converted solution file.
		/// </summary>
		/// <param name="solutionFile">The solution file.</param>
		/// <returns></returns>
		private string GetConvertedSolutionFile(FileInfo solutionFile)
		{
			string solutionContent = File.ReadAllText(solutionFile.FullName);
			solutionContent = solutionContent.Replace("Microsoft Visual Studio Solution File, Format Version 10.00\r\n# Visual Studio 2008", "Microsoft Visual Studio Solution File, Format Version 9.00\r\n# Visual Studio 2005");
			return solutionContent;
		}

		/// <summary>
		/// Get projects list from solution file
		/// </summary>
		/// <param name="rootFolder">Root folder which contain *.sln file</param>
		/// <returns></returns>
		public static List<ProjectInfo> GetProjectsList(string rootFolder)
		{
			if (!string.IsNullOrEmpty(rootFolder) && System.IO.Directory.Exists(rootFolder))
			{
				IEnumerable<string> solutions = from file in Directory.EnumerateFiles(rootFolder)
												where System.IO.Path.GetExtension(file) == ".sln"
												select file;

				if (solutions.Count() == 0)
					return null;

				using (StreamReader sr = new StreamReader(solutions.First()))
				{
					List<ProjectInfo> projects = new List<ProjectInfo>();

					string readLine = string.Empty;

					while ((readLine = sr.ReadLine()) != null)
					{
						if (readLine.Contains("Project(\""))
						{
							int equalsIndex = readLine.IndexOf('=');
							int firstDot = readLine.IndexOf(',');
							string project = readLine.Substring(equalsIndex + 1, (firstDot - equalsIndex) - 1).Replace('"', ' ').Trim();

							string[] splitedData = readLine.Split(',');
							ProjectInfo info = new ProjectInfo(project, splitedData[1].Replace('"', ' ').Trim(),
																splitedData[2].Replace('"', ' ').Trim());
							projects.Add(info);
						}
					}

					return projects;
				}
			}
			return null;
		}

		/// <summary>
		/// Get detailed info about project
		/// </summary>
		/// <param name="project">path to *.csproj file</param>
		/// <returns></returns>
		public static DetailedProjectInfo GetDeatiledProjectInfos(string project)
		{
			if (string.IsNullOrEmpty(project) || string.Compare(System.IO.Path.GetExtension(project), ".vdproj", true) == 0)
				return null;

			else if (!string.IsNullOrEmpty(project) && System.IO.File.Exists(project))
			{
				DetailedProjectInfo info = new DetailedProjectInfo();
				info.ProjectName = System.IO.Path.GetFileNameWithoutExtension(project);
				info.ProjectRootPath = System.IO.Path.GetDirectoryName(project);

				System.Xml.XmlDocument xd = null;
				System.Xml.XmlNamespaceManager xnsm = null;
				System.Xml.XmlNode xn = null;
				System.Xml.XmlNodeList nodeList = null;

				xd = new XmlDocument();
				xd.Load(project);

				xnsm = new System.Xml.XmlNamespaceManager(new System.Xml.NameTable());
				xnsm.AddNamespace("prj", "http://schemas.microsoft.com/developer/msbuild/2003");

				// let's do a quick sanity check to make sure we've got the
				// version that we're expecting.  Hey, it happens
				xn = xd.SelectSingleNode("/prj:Project", xnsm);
				if (xn != null)
				{
					info.ToolVersion = xn.Attributes["ToolsVersion"].Value;
				}

				//Get PropertyGroup project node
				XmlNode projNode = xd.SelectNodes("/prj:Project/prj:PropertyGroup", xnsm)[0];
				if (projNode != null)
				{
					info.AssemblyName = projNode.SelectSingleNode("prj:AssemblyName/text()", xnsm).Value;
					info.RootNamespace = projNode.SelectSingleNode("prj:RootNamespace/text()", xnsm).Value;
					info.ProductVersion = projNode.SelectSingleNode("prj:ProductVersion/text()", xnsm).Value;
					info.OutputType = projNode.SelectSingleNode("prj:OutputType/text()", xnsm).Value;
					if (projNode.SelectSingleNode("prj:TargetFrameworkVersion", xnsm) != null)
						info.TargetFrameworkVersion = projNode.SelectSingleNode("prj:TargetFrameworkVersion/text()", xnsm).Value;
					if (projNode.SelectSingleNode("prj:TargetFrameworkProfile", xnsm) != null)
						info.TargetFrameworkProfile = projNode.SelectSingleNode("prj:TargetFrameworkProfile", xnsm).InnerText;
					//get some additional info about publishing
					if (projNode.SelectSingleNode("prj:PublishUrl", xnsm) != null)
						info.PublishUrl = projNode.SelectSingleNode("prj:PublishUrl/text()", xnsm).Value;
					if (projNode.SelectSingleNode("prj:InstallUrl", xnsm) != null)
						info.InstallUrl = projNode.SelectSingleNode("prj:InstallUrl/text()", xnsm).Value;

					//Check if project have autogenerated resources file
					info.ContainsResourceFile = xd.ContainsResourceFile(xnsm);
					if (info.ContainsResourceFile)
					{
						//populate info about resources files
						info.ResoucesFiles = xd.GetResourceFile(xnsm);
					}
				}

				//Select ItemGroup nodes wich contains info about references and compiled items
				nodeList = xd.SelectNodes("/prj:Project/prj:ItemGroup", xnsm);
				if (nodeList != null && nodeList.Count > 1)
				{
					XmlNode referencesNode = nodeList[0];
					XmlNodeList tmp = referencesNode.SelectNodes("prj:Reference", xnsm);
					foreach (XmlNode n in tmp)
					{
						ReferenceInfo refinfo = new ReferenceInfo(); // get detailed info about reference
						if (n.HasChildNodes)
						{
							if (n.SelectSingleNode("prj:SpecificVersion", xnsm) != null)
								refinfo.IsSpecificVersion = n.SelectSingleNode("prj:SpecificVersion/text()", xnsm).Value.Trim() == "true" ? true : false;
							if (n.SelectSingleNode("prj:HintPath", xnsm) != null)
								refinfo.HintPath = n.SelectSingleNode("prj:HintPath/text()", xnsm).Value.Trim();
							if (n.SelectSingleNode("prj:RequiredTargetFramework", xnsm) != null)
								refinfo.RequiredFramework = n.SelectSingleNode("prj:RequiredTargetFramework/text()", xnsm).Value.Trim();
						}
						refinfo.Name = n.Attributes["Include"].Value.Trim();
						info.References.Add(refinfo);
					}
				}

				//create temporary xml document wich contains info about project files(compiled , pages etc)
				XmlDocument tempXmlDoc = new XmlDocument();
				XmlDeclaration xmldecl;
				xmldecl = tempXmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
				tempXmlDoc.AppendChild(xmldecl);
				XmlElement projItemsElement = tempXmlDoc.CreateElement("ProjectItems", "http://schemas.microsoft.com/developer/msbuild/2003");
				XmlElement pagesElement = tempXmlDoc.CreateElement("Pages", "http://schemas.microsoft.com/developer/msbuild/2003");
				projItemsElement.AppendChild(pagesElement);
				tempXmlDoc.AppendChild(projItemsElement);


				foreach (XmlNode tN in nodeList)
				{
					var compileList = tN.SelectTypedNodes("prj:Compile", xnsm);
					var pagesList = tN.SelectTypedNodes("prj:Page", xnsm);

					if (compileList != null && compileList.Count > 0)
					{
						//get reference to ProjectItems xml node
						var projItemsNode = tempXmlDoc.ChildNodes[1];

						foreach (XmlNode compNode in compileList)
						{
							XmlElement element = tempXmlDoc.CreateElement("Compile");
							XmlAttribute atr = tempXmlDoc.CreateAttribute("Include");
							atr.Value = compNode.Attributes["Include"].Value;
							element.Attributes.Append(atr);
							if (compNode.HasChildNodes)
							{
								foreach (XmlNode subNod in compNode)
								{
									switch (subNod.Name.Trim())
									{
										case "DependentUpon":
											XmlElement depUpon = tempXmlDoc.CreateElement("DependentUpon");
											XmlText text = tempXmlDoc.CreateTextNode(subNod.InnerText);
											depUpon.AppendChild(text);
											element.AppendChild(depUpon);
											break;
										case "SubType":
											XmlElement subType = tempXmlDoc.CreateElement("SubType");
											subType.InnerText = subNod.InnerText;
											element.AppendChild(subType);
											break;
										default:
											break;
									}
								}
							}
							projItemsNode.AppendChild(element);
						}
					}
					if (pagesList != null && pagesList.Count > 0)
					{
						//get reference to Pages xml node
						var pagesNode = tempXmlDoc.SelectSingleNode("/prj:ProjectItems/prj:Pages", xnsm);

						foreach (XmlNode pageNode in pagesList)
						{
							XmlElement pageElement = tempXmlDoc.CreateElement("Page");
							XmlAttribute atr = tempXmlDoc.CreateAttribute("Include");
							atr.Value = pageNode.Attributes["Include"].Value;
							pageElement.Attributes.Append(atr);

							if (pageNode.HasChildNodes)
							{
								foreach (XmlNode subNode in pageNode)
								{
									switch (subNode.Name.Trim())
									{
										case "SubType":
											XmlElement subType = tempXmlDoc.CreateElement("SubType");
											subType.InnerText = subNode.InnerText;
											pageElement.AppendChild(subType);
											break;

										case "Generator":
											XmlElement generator = tempXmlDoc.CreateElement("Generator");
											XmlText text = tempXmlDoc.CreateTextNode(subNode.InnerText);
											generator.AppendChild(text);
											pageElement.AppendChild(generator);
											break;
										default: break;
									}
								}
							}
							pagesNode.AppendChild(pageElement);
						}
					}
				}

				//Parse temporary xml document and populate infos about pages and compile files
				if (tempXmlDoc.ChildNodes[1].ChildNodes.Count > 0)
				{
					//populate list of compiled files
					foreach (XmlNode node in tempXmlDoc.ChildNodes[1])
					{
						if (node.Name == "Compile")
						{
							ProjectFileInfo pfInfo = new ProjectFileInfo();
							pfInfo.File = node.Attributes["Include"].Value;
							if (node.HasChildNodes)
							{
								pfInfo.DependentUpon = node.FirstChild.InnerText;
								if (node.ChildNodes[1] != null)
									pfInfo.SubType = node.ChildNodes[1].InnerText;
							}
							info.CompiledFiles.Add(pfInfo);
						}
						else if (node.Name == "Pages")
						{
							foreach (XmlNode page in node.ChildNodes)
							{
								PageInfo pageInfo = new PageInfo();
								pageInfo.Page = page.Attributes["Include"].Value;
								if (node.HasChildNodes)
								{
									pageInfo.SubType = page.FirstChild.InnerText;
									if (page.ChildNodes[1] != null)
										pageInfo.Generator = page.ChildNodes[1].InnerText;
								}
								info.Pages.Add(pageInfo);
							}
						}
					}
				}
				return info;
			}

			return null;
		}

		/// <summary>
		/// Get solution name
		/// </summary>
		/// <param name="solutionRootFolder">Container folder where *.sln file persists</param>
		/// <returns>Solution name</returns>
		public static string GetSolutionName(string solutionRootFolder)
		{
			if (!string.IsNullOrEmpty(solutionRootFolder) && System.IO.Directory.Exists(solutionRootFolder))
			{
				IEnumerable<string> solutions = from file in Directory.EnumerateFiles(solutionRootFolder)
												where System.IO.Path.GetExtension(file) == ".sln"
												select file;

				if (solutions.Count() == 0)
					return string.Empty;

				return System.IO.Path.GetFileNameWithoutExtension(solutions.First());
			}
			return string.Empty;
		}

	}
}
